import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import com.thoughtworks.xstream.XStream;

public class boggleGame {
	private board gameBoard;
	private List<String> existingWords;
	private List<player> players;
	private List<String> commonWords;
	private int currentPlayer;
	private long timeRemaining;

	//New Game with RANDOM board
	public boggleGame(int boardSize, List<String> wordList, List<player> players){
		//Remove duplicates from word list
		Set wordSet = new LinkedHashSet(wordList);
		wordList.clear();
		wordList.addAll(wordSet);
		//Sort word list alphabetically
		Collections.sort(wordList);
		
		this.players = players;
		this.commonWords = new ArrayList<String>();

		//Ensures game has at least 20 words
		existingWords = new ArrayList<String>();
		//while(existingWords.size() < 20){
			this.gameBoard = new board(boardSize);
			this.existingWords = findExistingWords(wordList);
		//}
		
		this.currentPlayer = 0;
		resetTime();
	}

	//New Game with CUSTOM board
	public boggleGame(List<Character[]> letters, List<String> wordList, List<player> players){
		//Remove duplicates from word list
		Set wordSet = new LinkedHashSet(wordList);
		wordList.clear();
		wordList.addAll(wordSet);
		//Sort word list alphabetically
		Collections.sort(wordList);
		
		this.players = players;
		this.gameBoard = new board(letters);
		this.commonWords = new ArrayList<String>();
		this.existingWords = findExistingWords(wordList);
		
		this.currentPlayer = 0;
		resetTime();
	}

	//Finds existing words
	public List<String>findExistingWords(List<String> wordList){
		List<String> existingWords;
		existingWords = new ArrayList<String>();

		String nonExistingWord = null;
		for(String word: wordList){
			Boolean check = true;

			if(word.length() < 3){
				check = false;
				nonExistingWord = null;
			}
			if(nonExistingWord != null){
				if(word.toUpperCase().startsWith(nonExistingWord.toUpperCase())){
					check = false;
				}
			}
			if(check == true)
			{
				int longestLetter = gameBoard.wordExists(word, false);
				if(longestLetter == word.length()){
					existingWords.add(word.toUpperCase().trim());
					nonExistingWord = null;
				}
				else{
					nonExistingWord = word.substring(0, longestLetter + 1);
				}
			}
		}
		return existingWords;
	}

	//Returns Existing Words
	public List<String>getExistingWords(){
		return existingWords;
	}

	//Returns current game board
	public board getCurrentBoard(){
		return gameBoard;
	}

	//Returns word number of words per word length
	public int[] getWordStats(){
		int[] wordStats = new int[6];
		for(int i = 0; i<6 ; i++) {
			wordStats[i] = 0;
		}
		for(String word : getExistingWords()){
			switch (word.length()){
			case 3 : wordStats[0]++; break;
			case 4 : wordStats[0]++; break;
			case 5 : wordStats[1]++; break;
			case 6 : wordStats[2]++; break;
			case 7 : wordStats[3]++; break;
			case 8 : wordStats[4]++; break;
			default : wordStats[5]++; break;
			}
		}
		return wordStats;
	}

	//Returns Players
	public List<player> getPlayers(){
		return players;
	}

	//Returns common words
	public List<String> getCommonWords(){
		return commonWords;
	}

	//Generates Results
	public void generateResults(){
		//Get common words among players
		commonWords = new ArrayList<String>();
		if(getPlayers().size() > 1 ){
			commonWords.addAll(getPlayers().get(0).getGuessedWords());
			for(player play : getPlayers()){
				commonWords.retainAll(play.getGuessedWords());
			}
			commonWords.retainAll(existingWords);
			Collections.sort(commonWords);
		}

		//Get accepted words per player
		for(player play : getPlayers()){
			List<String> acceptedWords = new ArrayList<String>();
			acceptedWords.addAll(getExistingWords());
			acceptedWords.retainAll(play.getGuessedWords());
			acceptedWords.removeAll(getCommonWords());
			play.setAcceptedWords(acceptedWords);
		}
	}

	//Saves game
	public void saveGame(String filePath) {
		XStream xstream = new XStream();
		
		String xml = xstream.toXML(this);
		
		try {
			PrintWriter out = new PrintWriter(filePath);
			out.print(xml);
			out.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
	}
	
	//Get Current Player
	public int getCurrentPlayer(){
		return this.currentPlayer;
	}
	
	//Sets Current player
	public void setCurrentPlayer(int currentPlayer){
		this.currentPlayer = currentPlayer;
	}
	
	//Get Time Remaining
	public long getTimeRemaining() {
		return timeRemaining;
	}

	//Set Time Remaining
	public void setTimeRemaining(long timeRemaining) {
		this.timeRemaining = timeRemaining;
	}
	
	//Get total number of players
	public int getTotalPlayers(){
		return players.size();
	}
	
	//Reset Time Remaining
	public void resetTime(){
		this.setTimeRemaining(180 + ((gameBoard.getBoardSize() - 4) * 30));
	}
	
	//Returns true if word was guessed by a player
	public Boolean wordGuessed(String word){
		for(player play : getPlayers()){
			for(String guess : play.getAcceptedWords()){
				if(guess.toUpperCase().trim().equals(word.toUpperCase().trim())){
					return true;
				}
			}
		}
		for(String commonWord : getCommonWords()){
			if(commonWord.toUpperCase().trim().equals(word.toUpperCase().trim())){
				return true;
			}
		}
		return false;
	}
}
